#pragma once 
#include <bits/stdc++.h>

/*****************************************************************************
 *! @brief 常见互斥量的特性与使用,主要包括:
 *      1. std::mutex                      独占互斥量
 *      2. std::recursive_mutex            独占递归互斥量
 *      3. std::timeout_mutex              带超时的独占互斥量
 *      4. std::timeout_recursive_mutex    带超时的独占递归互斥量
 * 
 *  
 ****************************************************************************/

std::mutex           g_mutex;
std::recursive_mutex g_recursive_mutex;
std::timed_mutex     g_timeout_mutex;

//! 普通互斥
void func() {
    //! 该代码会阻塞当前线程，进行无限期等待
    g_mutex.lock();                              // 获取该锁的线程才能执行后续的代码
    std::cout << "entering thread" << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "leaving thread"  << std::this_thread::get_id() << std::endl;
    g_mutex.unlock();
}


void func_lock_guard() {
    std::lock_guard<std::mutex> locker(g_mutex);  // 出作用域后自动解锁
    std::cout << "entering thread" << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "leaving thread"  << std::this_thread::get_id() << std::endl;
}


//! 2. 递归互斥锁
struct Complex {
	std::mutex mutex;                         // v1
    // std::recursive_mutex mutex;            // v2
	int i;

	Complex() : i(0){}

	void mul(int x) {
		std::lock_guard<std::mutex> lock(mutex);                   // v1
        // std::lock_guard<std::recursive_mutexex> lock(mutex);    // v2
		i *= x;
	}

	void div(int x) {
		std::lock_guard<std::mutex> lock(mutex);                   // v1
        // std::lock_guard<std::recursive_mutexex> lock(mutex);    // v2
		i /= x;
	}

    // Error: 运行锁死
	// void both(int x, int y) {
	// 	std::lock_guard<std::mutex> lock(mutex);
	// 	mul(x);
	// 	div(y);
	// }

    // v1: 
    void both(int x, int y) {
		std::lock_guard<std::mutex> lock(mutex);
		i *= x;
        i /= y;
	}

    // v2:  替换g_mutex为g_recursive_mutex；
    /**
     *! @brief  尽量不要用递归锁, 主要原因如下:
     *!
     *!    1). 需要用递归锁的多线程互斥本身是可以简化的;
     *!    2). 递归锁比非递归锁效率会低一些;
     *!    3). 递归本来有深度限制, 但递归的锁没有说可以有多少层; 超过次数会出现系统错误
     *!  
     */
    // void both(int x, int y) {
	// 	std::lock_guard<std::recursive_mutex> lock(g_recursive_mutex);
	// 	mul(x);
	// 	div(y);
	// }
};

//! 3. 超时互斥
void work() {
	std::chrono::milliseconds timeout(100);

	while (true) {
        /**
         *! @brief  try_lock_for(timeout) 的意思是阻塞等待特定的时间, 以获得锁. 其执行结果可能有:
         * 
         *     1. 锁被成功获得：在指定时间内获得了锁。一旦获得锁，线程可以持有锁任意长的时间，直到它调用 unlock()。
         *     2. 指定时间过去，但锁未被获得：如果在指定的时间段内锁没有变为可用状态，try_lock_for 会返回 false，且线程不会获得锁。
         *     3. 其他线程已经持有锁：如果在调用 try_lock_for 时，另一个线程已经持有了锁，则当前线程会等待，直到锁被释放或超时发生。
         */
		if (g_timeout_mutex.try_lock_for(timeout)) {
			std::cout << std::this_thread::get_id() << ": do work with the mutex"    << std::endl;

			std::chrono::milliseconds sleepDuration(250);
			std::this_thread::sleep_for(sleepDuration);

			g_timeout_mutex.unlock();
			std::this_thread::sleep_for(sleepDuration);
		} else {
			std::cout << std::this_thread::get_id() << ": do work without the mutex" << std::endl;
			std::chrono::milliseconds sleepDuration(100);
			std::this_thread::sleep_for(sleepDuration);
		}
	}
}

int std_mutex();